iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
自我挑戰組

新手前端與真實世界的開發 feat.React 與他的夥伴系列 第 14

Day-14 專案演練 - React 拆元件的思路與操作(下)

  • 分享至 

  • xImage
  •  

Day-14 專案演練 - React 拆元件的思路與操作(下)

沒想到拆元件居然真的講了三天。在實作的時候常常會感覺跳過很多步驟,但實際上沒有跳,只是每個步驟都做得好快,有些甚至可以一起進行,也就是說,只要熟練了之後,就會忘記當初不熟的時候有多麼卡住...今天在做的時候,又想起了一些可能該知道的事情,就在這篇文章跟大家分享看看吧。

大小寫區分的作用

元件都是用大寫來作為開頭,資料夾名稱則是都用小寫,算是一種取名字慣例,一開始我在寫程式的時候,也不知道為什麼要這樣做,後來才發現這樣做其實有一些方便的地方。

  • 導出與導入模組的時候可以起到一個標記的作用
  • 只要看到是大寫就知道是元件了

語意化的 HTML 標籤

其實,全部都用 div 也能把版切好。

當堆疊了太多的標籤,鑲嵌的又太深的時候,常常會很混亂,所以跟大家分享我自己使用語意化標籤的方法。

  • <section>用在 Page 的最外層,與 <div> 形成區別
  • <ul><li> 代表有序的清單,我通常會在 Menu 或者有相關的元件集合裡面去用它
  • <dl>也是清單,但與上一位不同的是,它的子元件有 <dt><dd>,前者代表一個標題,後者就沒有標題的意思
  • 偶爾我會用到 <time> 這樣的標籤,而且這個標籤是真的有,就只是用來告訴大家裡面包的是時間

對於 HomePage 的新想法

製作了 TodoPage 跟 DashboardPage 之後,對於 HomePage 有了點新的靈感。

所以修改了原本畫過的 Function Map,加上了快速新增一則 todo 的區塊,而且因為 DashboardPage 設計出來了,所以覺得可以將各個櫃子概略的狀態放上來,就能一目了然。

安裝 modal 的 UI 套件

接下來我要使用 modal 彈跳視窗的方式,來做新增 todo 的 UI。

我很討厭 modal,從我在純切版,手刻 RWD 的時期就已經是這樣,手刻得出來,但就是很煩。

後來我習慣用一個套件來幫助我做 modal,就是 Reach UI 裡面的 Dialog(Modal),嘗試了很多個最後用的最順手的就是它了。

因為很多 UI 庫都會有 Modal 可以用,只要用自己喜歡的那個就行了。

跟著官方文件來安裝,總之用自己順手的套件管理工具 :

npm install @reach/dialog
# or
yarn add @reach/dialog

引入 :

import { Dialog, DialogOverlay, DialogContent } from "@reach/dialog";
import "@reach/dialog/styles.css";

加入讓 tailwind 能對 form 樣式修改的套件

接下來會用到表單樣式,但 tailwind 原來是不能動表單樣式的,這個時候我們需要安裝一個 tailwind plugin,@tailwindcss/forms

安裝 @tailwindcss/forms 到專案裡面 :

npm install -D @tailwindcss/forms

然後到 tailwind.config.js 把它掛上去 :

// tailwind.config.js
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require("@tailwindcss/forms"),
    // ...
  ],
};

加上彈跳視窗功能元件 - modal

以上都安裝完畢,要再專案裡面使用 modal 囉。

首先,在 components 資料新增 Modal.tsx :

import { Dialog } from "@reach/dialog";
import "@reach/dialog/styles.css";

const Modal = ({ children, isOpen }) => {
  return (
    <Dialog className="w-[40%]" isOpen={isOpen}>
      {children}
    </Dialog>
  );
};

export default Modal;

再回到要使用 modal 的頁面,也就是 TodoPage,把 Modal 引入之後,再已經切好的表單放進去,因為切版已經做過了,所以我就不再贅述:

...
<Modal isOpen={isOpen}>
  <div className="flex justify-end">
    <span
      className="
          font-medium
          cursor-pointer
          inline-block
          bg-gray-200
          w-[24px] text-center rounded"
      onClick={() => setIsOpen(false)}
    >
      X
    </span>
  </div>

  <div className="py-12 flex flex-col justify-center items-center">
    <h2 className="text-2xl font-bold">新增待辦</h2>
    <div className="mt-8">
      <div className="grid grid-cols-1 gap-[8px] w-[340px]">
        <label className="block ">
          <span className="text-gray-700">標題</span>
          <input
            type="text"
            className="
                    mt-1
                    block
                    w-full
                    rounded-md
                    bg-gray-100
                    border-transparent
                    focus:border-gray-500 focus:bg-white focus:ring-0
                  "
          />
        </label>

        <label className="block">
          <span className="text-gray-700">時間</span>
          <input
            type="date"
            className="
                    mt-1
                    block
                    w-full
                    rounded-md
                    bg-gray-100
                    border-transparent
                    focus:border-gray-500 focus:bg-white focus:ring-0
                  "
          />
        </label>
        <label className="block">
          <span className="text-gray-700">詳情描述</span>
          <textarea
            className="
                    mt-1
                    block
                    w-full
                    rounded-md
                    bg-gray-100
                    border-transparent
                    focus:border-gray-500 focus:bg-white focus:ring-0
                  "
            rows={3}
            defaultValue={""}
          />
        </label>
      </div>
    </div>
  </div>
</Modal>
...

新增 AddTodo 跳窗功能

我們需要一個 state 來控制彈跳視窗,所以新增一個 state 在 TodoPage,叫做 isOpen :

const [isOpen, setIsOpen] = useState(false);

在需要開啟的地方添加 setIsOpen(true),也就是 AddButton,不過在那之前,得修改 AddButton.tsx,讓他接受從外面傳進去的 onClick :

import React from "react";

const AddButton = ({ onClick }) => {
  return (
    <div className="flex items-center" onClick={onClick}>
      <svg
        width="32"
        height="32"
        viewBox="0 0 32 32"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <rect width="32" height="32" rx="6" fill="#EDF2F7" />
        <path
          d="M23.7918 16.5416H17.5418V22.7916H15.4585V16.5416H9.2085V14.4583H15.4585V8.20831H17.5418V14.4583H23.7918V16.5416Z"
          fill="black"
        />
      </svg>
      <span className="ml-[8px]">新增待辦</span>
    </div>
  );
};

export default AddButton;

在回來 TodoPage 來,為 AddButton 加入功能 :

<AddButton onClick={() => setIsOpen(true)} />

再來就是關掉 Modal 的 x 按鈕 :

    <span
      className="
          font-medium
          cursor-pointer
          inline-block
          bg-gray-200
          w-[24px] text-center rounded"
      onClick={() => setIsOpen(false)}
    >
      X
    </span>
  </div>

新增 HomePage

切完的 HomePage 如圖,程式碼也會給大家。

repo

附上程式碼

結語

好的,加上了一個含有添加新 todo 表單的彈跳視窗,下一個章節要來介紹表單的處理,會更仔細的來看看這些表單元素有什麼神奇之處。

參考資料


上一篇
Day-13 專案演練 - React 拆元件的思路與操作(中)
下一篇
Day-15 專案演練 - 打造表單功能 react-hook-form
系列文
新手前端與真實世界的開發 feat.React 與他的夥伴30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言